package jointpart.assignment4;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;

import com.javamex.classmexer.MemoryUtil;
import com.javamex.classmexer.MemoryUtil.VisibilityFilter;

import shared.*;

import jxl.Workbook;
import jxl.WorkbookSettings;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import writer.TestResult; // TestResult class for benchmarking
import writer.WriteExcel; // For writing benchmark to excel

/**
 * Test Assignment 4:
 * 	n calls to Searcher.hashMapFile measuring each call
 * 	n calls to getUrls ( 2 different words ) measuring each call
 * 	n calls to getUrls - measuring every test
 * 
 * All results are exported to an excel file
 * 
 */

@SuppressWarnings("unused")
public class Benchmark4 {

	// Variables for measuring time end memory
	long t1,t2,m1,m2;
	private static int SLEEP_SIZE = 100;
	int singleInt = 200; 	//default 200 times
	int listInt = 10; 	//default 30 times
	int memoryInt = 10;	//default 10 times
	int mexerInt = 10; 	//default 10 times

	/**
	 * Runs performance test of hashMapFile and getUrls
	 * in each test loop the garbage collector is emptied
	 * 
	 * @param l - HTMLWordList[] to use in test
	 * @param inputFile, File to read in
	 * @param outputFile, target file for benchmarking
	 * @throws FileNotFoundException
	 * 
	 */
	public void runBenchmark(WordList[] l, String inputFile, String outputFile) throws FileNotFoundException{

		ArrayList<TestResult> singleBenchmark = new ArrayList<TestResult>();

		putOutTheGarbage(); // empty garbage collector before next test

		// Perform time measure 200 times
		for (int i = 1 ; i <= singleInt ; i++) {

			t1 = System.nanoTime(); // setoff time

			String tmp = Searcher4.getUrls(l, "home");
			tmp = Searcher4.getUrls(l, "aCompleteStrangeWord");

			t2 = System.nanoTime(); // end time

			// Add result to Arraylist 
			singleBenchmark.add(new TestResult(i, t2-t1 ));

			putOutTheGarbage(); // empty garbage collector before next iteration

		}

		ArrayList<TestResult> listBenchmark = new ArrayList<TestResult>(); // results of test

		putOutTheGarbage(); // empty garbage collector before first test

		// Measure performance of readWordListList 30 times
		for (int i = 1 ; i <= listInt ; i++) {
			t1 = System.nanoTime(); // setoff time
			try {

				WordList[] test = Searcher4.hashMapFile(inputFile, 200);

			} catch (IOException e) {
				e.printStackTrace();
			}

			t2 = System.nanoTime(); // end time

			// Add result to Arraylist 
			listBenchmark.add(new TestResult(i, t2-t1 ));

			putOutTheGarbage(); // empty garbage collector before next iteration

		}


		// Create ArrayList for MultiBenchmark
		ArrayList<TestResult> memoryBenchmark = new ArrayList<TestResult>();

		putOutTheGarbage(); // Clean up garbage

		// Memory space performance benchmark 10 times

		for (int i = 1 ; i <= memoryInt ; i++ ) {

			// Memory use before calling method

			m1 = getMemoryUse();

			try {

				WordList[] test = Searcher4.hashMapFile(inputFile, 200);

			} catch (IOException e) {
				e.printStackTrace();
			}

			// Memory use after calling method
			m2 = getMemoryUse();

			// add result to ArrayList of results
			memoryBenchmark.add(new TestResult(i, m2-m1 ));

		}


		// Create ArrayList for Classmexer benchmark - testing deep memory of objects
		ArrayList<TestResult> classmexerBenchmark = new ArrayList<TestResult>();

		putOutTheGarbage(); // Clean up garbage

		for (int i = 1 ; i <= mexerInt ; i++ ) {

			try {
				WordList[] test4 = Searcher4.hashMapFile(inputFile, 200);

				//number of bytes - deep memory use
				long noBytes = MemoryUtil.deepMemoryUsageOf(test4, VisibilityFilter.ALL);

				// add result to ArrayList of results
				classmexerBenchmark.add(new TestResult(i, noBytes));

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			putOutTheGarbage(); //clean up garbage after each iteration
		}


		// Create new Excel Workbook and write results
		WriteExcel testReport = new WriteExcel();
		File file = new File(outputFile + ".xls");

		WorkbookSettings wbSettings = new WorkbookSettings();
		wbSettings.setLocale(new Locale("en", "EN"));

		try {

			WritableWorkbook workbook = Workbook.createWorkbook(file, wbSettings);

			testReport.addSheet(workbook, "List Benchmark", listBenchmark, "test no." , "Time in Nanosec");
			testReport.addSheet(workbook, "Single Benchmark", singleBenchmark, "test no." , "Time in Nanosec");
			testReport.addSheet(workbook, "Memory Benchmark", memoryBenchmark, "n", "Bytes");
			testReport.addSheet(workbook, "Classmexer Benchmark", classmexerBenchmark, "test no.", "Bytes - SearchCmd4");
			workbook.write();
			workbook.close();

		} catch (IOException e1) {
			e1.printStackTrace();

		} catch (WriteException w1) {
			w1.printStackTrace();
		}

	}

	private static long getMemoryUse() {

		putOutTheGarbage();
		long totalMemory = Runtime.getRuntime().totalMemory();
		putOutTheGarbage();
		long freeMemory = Runtime.getRuntime().freeMemory();

		return (totalMemory - freeMemory);
	}

	private static void putOutTheGarbage(){
		collectGarbage();
		collectGarbage();
	}

	private static void collectGarbage() {
		try {
			System.gc();
			Thread.currentThread();
			Thread.sleep(SLEEP_SIZE);
			System.runFinalization();
			Thread.sleep(SLEEP_SIZE);
		}

		catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}

}
